

/**
 * @file SatArcMarker.cpp
 * This class keeps track of satellite arcs caused by cycle slips.
 */

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2008, 2009, 2011
//
//============================================================================


#include "SatArcMarker.hpp"

#define debug 0

namespace gpstk
{

      // Return a string identifying this object.
    std::string SatArcMarker::getClassName() const
    { return "SatArcMarker"; }


      /* Method to get the arc changed epoch.
       * @param sat              Interested SatID.
       */
    CommonTime SatArcMarker::getArcChangedEpoch(const SatID& sat)
    {
        SatArcData::iterator it = m_satArcData.find(sat);
        if(it != m_satArcData.end())
        {
            return it->second.arcChangeTime;
        }
        else
        {
            return CommonTime::BEGINNING_OF_TIME;
        }

    }  // End of method 'SatArcMarker::getArcChangedEpoch()'


      /* Method to get the arc changed epoch.
       * @param source           Interested SourceID.
       * @param sat              Interested SatID.
       */
    CommonTime SatArcMarker::getArcChangedEpoch(const SourceID& source,
                                                const SatID& sat)
    {
        SatArcDataMap::iterator it = m_satArcDataMap.find(source);

        if(it != m_satArcDataMap.end())
        {
            m_satArcData = it->second;

            return getArcChangedEpoch( sat );
        }
        else
        {
            return CommonTime::BEGINNING_OF_TIME;
        }

    }  // End of method 'SatArcMarker::getArcChangedEpoch()'


      /* Return a satTypeValueMap object, adding the new data generated
       *  when calling this object.
       *
       * @param epoch     Time of observations.
       * @param gData     Data object holding the data.
       */
    satTypeValueMap& SatArcMarker::Process( const CommonTime& epoch,
                                            satTypeValueMap& gData )
        noexcept(false)
    {
        try
        {
            SatIDSet satRejectedSet;

            // Loop through all the satellites
            for ( satTypeValueMap::iterator it = gData.begin();
                  it != gData.end();
                  ++it )
            {
                SatID sat = (*it).first;

                double flagLC(0.0), flagWL(0.0);
                double flagMW(0.0), flagLI(0.0);
                double flagL1(0.0), flagL2(0.0);

                bool findLC(false), findWL(false), 
                     findMW(false), findLI(false),
                     findL1(false), findL2(false) ;

                bool findCS(false);
                double flagCS(0.0);

                if( (*it).second.find(TypeID::CSFlag) != (*it).second.end() )
                {
                    findCS = true;
                    flagCS = (*it).second(TypeID::CSFlag);
                }


                if( (*it).second.find(TypeID::CSLC) != (*it).second.end() )
                {
                    findLC = true;
                    flagLC = (*it).second(TypeID::CSLC);
                }

                if( (*it).second.find(TypeID::CSWL) != (*it).second.end() )
                {
                    findWL = true;
                    flagWL = (*it).second(TypeID::CSWL);
                }

                if( (*it).second.find(TypeID::CSMW) != (*it).second.end() )
                {
                    findMW = true;
                    flagMW = (*it).second(TypeID::CSMW);
                }

                if( (*it).second.find(TypeID::CSLI) != (*it).second.end() )
                {
                    findLI = true;
                    flagLI = (*it).second(TypeID::CSLI);
                }

                if( (*it).second.find(TypeID::CSL1) != (*it).second.end() )
                {
                    findL1 = true;
                    flagL1 = (*it).second(TypeID::CSL1);
                }

                if( (*it).second.find(TypeID::CSL2) != (*it).second.end() )
                {
                    findL2 = true;
                    flagL2 = (*it).second(TypeID::CSL2);
                }

                if( !findLC && !findWL && !findMW && !findLI && !findL1 && !findL2)
                {
                    cerr << "cycle slip flags not found in satData!" << endl;
                    exit(-1);
                }

                // Check if satellite currently has entries
                SatArcData::const_iterator itArc( m_satArcData.find( sat ) );
                if( itArc == m_satArcData.end() )
                {
                    // If it doesn't have an entry, insert one
                    m_satArcData[sat].arcChangeTime = CommonTime::BEGINNING_OF_TIME;
                    m_satArcData[sat].arcNum = 0.0;
                }

  
                // Check if there was a cycle slip
                // compatible with different cycle-slip method
                if ( 
                     (flagCS > 0.0) ||
                     (flagMW > 0.0) ||
                     (flagLI > 0.0) ||
                     (flagLC > 0.0) || 
                     (flagWL > 0.0) || 
                     (flagL1 > 0.0) ||
                     (flagL2 > 0.0) 
                     )
                {
  
                    if(csDataStream!=NULL)
                    {
                        (*csDataStream) 
                            << sat  << " "
                            << YDSTime(epoch) << " "
                            << flagLC << " "
                            << flagMW << " "
                            << endl;
                    }
  
  

                    // Increment the value of "TypeID::satArc"
                    m_satArcData[sat].arcNum = m_satArcData[sat].arcNum + 1.0;

                    // Update arc change epoch
                    m_satArcData[sat].arcChangeTime = epoch;
                }

                if(debug)
                {
                    cout << "satArcMarker:" << sat << ":" << m_satArcData[sat].arcNum << endl;
                }

                // We will insert satellite arc number
                (*it).second[TypeID::satArc] = m_satArcData[sat].arcNum;

            }

            // Remove satellites with missing data
            gData.removeSatID(satRejectedSet);

            return gData;
        }
        catch(Exception& u)
        {
            // Throw an exception if something unexpected happens
            ProcessingException e( getClassName() + ":" + u.what() );
            GPSTK_THROW(e);
        }

    }  // End of method 'SatArcMarker::Process()'


      /* Return a gnssRinex object, adding the new data generated when
       *  calling this object.
       *
       * @param gData    Data object holding the data.
       */
    void SatArcMarker::Process(commonHeader& comHeader,gnssRinex& gData)
        noexcept(false)
    {

        try
        {
            Process(gData.header.epoch, gData.body);

        }
        catch(Exception& u)
        {
            // Throw an exception if something unexpected happens
            ProcessingException e( getClassName() + ":" + u.what() );
            GPSTK_THROW(e);
        }

    }  // End of method 'SatArcMarker::Process()'


     /** Return a sourceRinex object, adding the new data generated when
      *  calling this object.
      *
      * @param gData    Data object holding the data.
      */
    void SatArcMarker::Process(commonHeader& comHeader,sourceRinex& gData)
        noexcept(false)
    {

       for( sourceDataMap::iterator sdmIt = gData.body.begin();
            sdmIt != gData.body.end();
            ++sdmIt )
       {
           SourceID source( sdmIt->first );

           SatArcDataMap::iterator satArcDataIt = m_satArcDataMap.find(source);

           if( satArcDataIt != m_satArcDataMap.end() )
           {
               m_satArcData = satArcDataIt->second;
           }
           else
           {
               m_satArcData = SatArcData();
           }

           Process( gData.header.epoch, sdmIt->second );

           m_satArcDataMap[source] = m_satArcData;
       }

    }  // End of method 'SatArcMarker::Process()'


}  // End of namespace gpstk
